package xdu.lz.stage4_atomic.chapter7_unsafe;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created at 2019/10/17 0017 下午 11:03
 */
public class UnsafeDemo1 {

    interface Counter {
        void increment();

        long getCounter();
    }


    static class CounterRunnable implements Runnable {
        private final Counter counter;
        private final int num;
        CounterRunnable(Counter counter, int num) {
            this.counter = counter;
            this.num = num;
        }

        @Override
        public void run() {
            for (int i = 0; i < num; i++) {
                counter.increment();
            }
        }
    }

    static class EasyCounter implements Counter {

        private long counter = 0;

        @Override
        public void increment() {
            counter++;
        }

        @Override
        public long getCounter() {
            return this.counter;
        }
    }

    static class SynchronizedCounter implements Counter {
        private long counter = 0;
        @Override
        public synchronized void increment() {
            counter++;
        }
        @Override
        public long getCounter() {
            return this.counter;
        }
    }

    static class LockCounter implements Counter {

        private long counter = 0;

        private final Lock lock = new ReentrantLock();

        @Override
        public synchronized void increment() {
            try {
                lock.lock();
                counter++;
            } finally {
                lock.unlock();
            }
        }

        @Override
        public long getCounter() {
            return this.counter;
        }
    }


    static class AtomicCounter implements Counter {

        private AtomicLong counter = new AtomicLong(0);

        private final Lock lock = new ReentrantLock();

        @Override
        public synchronized void increment() {
            try {
                lock.lock();
                counter.incrementAndGet();
            } finally {
                lock.unlock();
            }
        }

        @Override
        public long getCounter() {
            return counter.get();
        }
    }

    static class CASCounter implements Counter {

        private volatile long counter = 0;

        private Unsafe unsafe;

        private long offset;

        public CASCounter() throws Exception {
            this.unsafe = getUnsafe();
            this.offset = unsafe.objectFieldOffset(CASCounter.class.getDeclaredField("counter"));
        }

        @Override
        public synchronized void increment() {
           for (;;){
               long current = counter;
               long newValue = current + 1;
               if(unsafe.compareAndSwapLong(this,offset,current,newValue)){
                   return;
               }
           }
        }

        @Override
        public long getCounter() {
            return counter;
        }
    }
    public static void main(String[] args) throws Exception {
//   不可直接拿     Unsafe unsafe = Unsafe.getUnsafe();
        ExecutorService service = Executors.newFixedThreadPool(1000);

        /**
         * Counter  result = 989038
         * 用时:451
         */
//        Counter counter = new EasyCounter();
        /**
         * Counter  result = 10000000
         * 用时:3902
         */
//        Counter counter = new SynchronizedCounter();
        /**
         * Counter  result = 10000000
         * 用时:6181
         */
//        Counter counter = new LockCounter();
        /**
         * Counter  result = 100000000
         * 用时:6724
         */
//        Counter counter = new AtomicCounter();
        /**
         * Counter  result = 100000000
         *  用时:3999
         */
        Counter counter = new CASCounter();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            //每个线程加1W次
            service.submit(new CounterRunnable(counter, 100000));
        }
        service.shutdown();
        //最多等1小时，没完成则关闭
        service.awaitTermination(1, TimeUnit.HOURS);
        System.out.println("Counter  result = " + counter.getCounter());
        System.out.println("用时:" + (System.currentTimeMillis() - start));
    }

    //通过反射拿到Unfase对象
    public static Unsafe getUnsafe() {

        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
